package xyz.xtt.pay.support;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import cn.hutool.core.util.IdUtil;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.pay.api.enums.PayOrderBusinessTypeEnum;
import xyz.xtt.pay.constants.ErrorMessage;
import xyz.xtt.pay.dto.PayCenterOrderStatusResponse;
import xyz.xtt.pay.dto.pay.GoodsInfo;
import xyz.xtt.pay.dto.pay.OpenOrderPrepayRequest;
import xyz.xtt.pay.dto.pay.PayNotifyRequest;
import xyz.xtt.pay.dto.pay.PayStatusQueryRequest;
import xyz.xtt.pay.entity.TblBusinessOrder;
import xyz.xtt.pay.entity.TblPayOrder;
import xyz.xtt.pay.exception.ChainException;
import xyz.xtt.pay.service.IInnerService;
import xyz.xtt.pay.utils.AESUtil;
import xyz.xtt.pay.utils.pay.HttpsUtils;
import xyz.xtt.pay.utils.pay.RSASignature;
import xyz.xtt.pay.utils.pay.SignatureHelper;
import xyz.xtt.pay.vo.PayCenterArgsResponse;
import xyz.xtt.pay.vo.PayCenterArgsResponseV3;
import xyz.xtt.pay.vo.PayCenterPayParamV3;
import xyz.xtt.user.client.response.UserInfoResponse;

/**
 * 支付中心相关http接口服务
 *
 * @author dale
 * @since 2024/12/30
 **/
@RefreshScope
@Slf4j
@Component
public class PayCenterV3HttpService {
    private static final String NFT_ORDER_PREFIX = "NFT_";
    private static final String PAY_CENTER_API_PROTOCOL = "https://";
    private static final String ORDER_REFUND_APPLY_PATH = "/nx2cloud/nx2cloud-app-pay/payOrderApi/payOrderRefund";
    private static final String PAY_ORDER_QUERY_PATH = "/nx2cloud/nx2cloud-app-pay/payOrderApi/payOrderQuery";

    @Value("${pay.center.v3.app.id}")
    private String appId;
    @Value("${pay.center.v3.mchId}")
    private String mchId;

    @Value("${pay.center.v3.api.host}")
    private String payCenterHost;

    @Value("${pay.center.v3.page.url}")
    private String payCenterPageUrl;

    @Value("${pay.center.v3.merchantPrivateKey}")
    private String privateKey;
    @Value("${pay.center.v3.platformPublicKey}")
    private String publicKey;
    @Value("${pay.notify.host}")
    private String notifyHost;
    @Autowired
    private IInnerService iInnerService;

    /**
     * 预下单
     * @param responseV2
     * @param goodsInfo
     * @return
     */
    public PayCenterArgsResponseV3 convertFromV2(PayCenterArgsResponse responseV2, GoodsInfo goodsInfo) throws Exception{
        OpenOrderPrepayRequest request = new OpenOrderPrepayRequest();
        request.setAppId(appId);
        request.setMchId(mchId);
        request.setOpenId(responseV2.getPayParam().getUserId());
        request.setTimestamp(getDateTime());
        request.setAmountTotal(new BigDecimal(String.valueOf(responseV2.getPayParam().getAmountTotal())));
        request.setAmount(request.getAmountTotal());
        request.setOrderNo(responseV2.getPayParam().getOrderNo());
        request.setNotifyUrl(notifyHost+"api/open/payNotify");
        request.setMobile(responseV2.getPayParam().getMobile());
        request.setOrderType(responseV2.getPayParam().getOrderType());
//        request.setIsSplitAccount(Objects.equals(responseV2.getPayParam().getOrderType(),NFT_ORDER_PREFIX+PayOrderBusinessTypeEnum.C_TO_C.name())?"Y":"N");
        request.setIsSplitAccount("N");
        List<GoodsInfo> goodsInfos = new ArrayList<>();
        goodsInfos.add(goodsInfo);
        request.setGoodsInfos(goodsInfos);
        //签名
        String waitSignature = SignatureHelper.prepareSignData(request);
        log.info("待签名数据:" + waitSignature);
        String sign = RSASignature.sign(waitSignature, privateKey);
        request.setSign(sign);
        String str = HttpsUtils.post(payCenterHost+"/nx2cloud/nx2cloud-app-pay/payOpenApi/preOrderPay", request);
        if(StringUtils.isNotBlank(str)){
            com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(str);
//            JSONObject jsonObject = JSONUtil.parseObj(str);
            if ("0".equals(jsonObject.getString("code"))) {
                com.alibaba.fastjson.JSONObject data = jsonObject.getJSONObject("data");
                String signResult = data.getString("sign");
                data.remove("sign");
                //排序
                String signData = SignatureHelper.prepareSignData(data.getInnerMap());
                log.info("待验签数据:" + signData);
                if (RSASignature.verify(signData, Base64.getDecoder().decode(signResult), publicKey)) {
                    log.info("验签成功");
                    PayCenterArgsResponseV3 responseV3 = new PayCenterArgsResponseV3();
                    BeanUtils.copyProperties(responseV2, responseV3,"payParam","payCenterVersion");
                    responseV3.setPayCenterUrl(payCenterPageUrl);
                    PayCenterPayParamV3 payParamV3 = new PayCenterPayParamV3();
                    payParamV3.setPrepayId(data.getString("prepayId"));
                    payParamV3.setAppId(appId);
                    payParamV3.setTimeStamp(request.getTimestamp());
                    payParamV3.setNonceStr(IdUtil.getSnowflakeNextIdStr());
                    payParamV3.setPackage_("prepayId="+data.getString("prepayId"));
                    payParamV3.setSignType("RSA");
                    payParamV3.setIsSplitAccount(request.getIsSplitAccount());
                    payParamV3.setPaymentResults(true);
                    payParamV3.setBackUrl(addOrderArgs(responseV2.getPayParam().getBackUrl(),request.getOrderNo()));
                    String waitSignature1 = SignatureHelper.prepareSignData(payParamV3);
                    waitSignature1 = waitSignature1.replace("package_=", "package=");
                    log.info("payParamV3 待签名数据:" + waitSignature1);
                    sign = RSASignature.sign(waitSignature1, privateKey);
                    payParamV3.setSign(sign);
                    responseV3.setPayParam(payParamV3);
                    return responseV3;
                } else {
                    log.error("验签失败");
                    throw new ChainException(ErrorMessage.ORDER_CREATE_FAILED);
                }
            } else {
                log.error("预下单失败，响应结果:{}", str);
                throw new ChainException(ErrorMessage.ORDER_CREATE_FAILED);
            }
        }else {
            log.error("预下单失败，响应结果为空");
            throw new ChainException(ErrorMessage.ORDER_CREATE_FAILED);
        }
    }

    private String addOrderArgs(String backUrl, String orderNo) {
        if(StringUtils.isBlank(backUrl)){
            log.error("回跳地址为空");
            throw new ChainException(ErrorMessage.ORDER_CREATE_FAILED);
        }
        if (backUrl.contains("?")){
            return backUrl+"&orderNo="+orderNo.substring(4);
        }
        return backUrl+"?orderNo="+orderNo.substring(4);
    }

    private String getDateTime() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    }

    public boolean checkNotifySign(PayNotifyRequest request) {
        String signResult = request.getSign();
        request.setSign(null);
        try {
            String signData = SignatureHelper.prepareSignData(request);
            log.info("待验签数据:" + signData);
            if (RSASignature.verify(signData, Base64.getDecoder().decode(signResult), publicKey)) {
                log.info("验签成功");
                return true;
            }
        }catch (Exception e){
            log.error("验签失败",e);
        }
        return false;
    }

    public PayCenterOrderStatusResponse queryPayStatus(Long payOrderId, String userId, String prepayId) {
        PayStatusQueryRequest request = new PayStatusQueryRequest();
        request.setAppId(appId);
        request.setMchId(mchId);
        request.setOpenId(userId);
        request.setOrderNo(NFT_ORDER_PREFIX+payOrderId);
        request.setTradeNo(prepayId);
        request.setTimestamp(getDateTime());
        request.setVersion("1.1");
        try {
            String waitSignature = SignatureHelper.prepareSignData(request);
            log.info("待签名数据:" + waitSignature);
            String sign = RSASignature.sign(waitSignature, privateKey);
            request.setSign(sign);
            log.info("签名:" + sign);
            String str = HttpsUtils.post(payCenterHost + "/nx2cloud/nx2cloud-app-pay/payOpenApi/queryOrderPay", request);
            if (StringUtils.isNotBlank(str)) {
//                JSONObject jsonObject = JSONUtil.parseObj(str);
                com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(str);
                if ("0".equals(jsonObject.getString("code"))) {
                    com.alibaba.fastjson.JSONObject data = jsonObject.getJSONObject("data");
                    String signResult = data.getString("sign");
                    data.remove("sign");
                    //排序
                    String signData = SignatureHelper.prepareSignData(data.getInnerMap());
                    log.info("待验签数据:" + signData);
                    if (RSASignature.verify(signData, Base64.getDecoder().decode(signResult), publicKey)) {
                        log.info("验签成功");
                        PayCenterOrderStatusResponse orderStatusResponse = new PayCenterOrderStatusResponse();
                        orderStatusResponse.setState(Integer.parseInt(data.getString("status")));
                        return orderStatusResponse;
                    } else {
                        log.error("验签失败");
                    }
                } else {
                    log.error("查询订单失败，响应结果:{}", str);
                }
            } else {
                log.error("查询订单失败，响应结果为空");
            }
        }catch (Exception e){
            log.error("查询订单失败",e);
        }
        return null;
    }
    /**
     * 预下单
     *
     * @param businessOrder
     * @param backUrl
     * @return
     */
    public PayCenterArgsResponseV3 prePay(TblBusinessOrder businessOrder, TblPayOrder payOrder, String backUrl) throws Exception{
    	UserInfoResponse user = iInnerService.userInfo(businessOrder.getAppUserId());
        String phone = user.getPhone();
        if (StringUtils.isNotBlank(phone)){
            try {
                phone = AESUtil.decrypt(phone);
            }catch (Exception e){
                log.error("decrypt phone error. phone:{} error:{}",phone,e);
            }
            if (phone.startsWith("86")){
                phone = phone.substring(2);
            }
        }

        OpenOrderPrepayRequest request = new OpenOrderPrepayRequest();
        request.setAppId(appId);
        request.setMchId(mchId);
        request.setOpenId(String.valueOf(businessOrder.getAppUserId()));
        request.setTimestamp(getDateTime());
        request.setAmountTotal(payOrder.getOrderMoney());
        request.setAmount(request.getAmountTotal());
        request.setOrderNo(NFT_ORDER_PREFIX+payOrder.getPayOrderId());
        request.setNotifyUrl(notifyHost+"api/open/payNotify/v2");
        request.setMobile(phone);
        request.setOrderType(NFT_ORDER_PREFIX + PayOrderBusinessTypeEnum.getByCode(payOrder.getBusinessType()).name());
//        request.setIsSplitAccount(Objects.equals(payOrder.getBusinessType(),PayOrderBusinessTypeEnum.C_TO_C.getCode())?"Y":"N");
        request.setIsSplitAccount("N");
        GoodsInfo goodsInfo = new GoodsInfo();
        goodsInfo.setGoodsId(businessOrder.getGoodsId());
        goodsInfo.setGoodsName(businessOrder.getGoodsName());
        boolean isPhysicalGoods =
                Objects.equals(payOrder.getBusinessType(),PayOrderBusinessTypeEnum.ASSET_WITH_PHYSICAL.getCode())
                        || Objects.equals(payOrder.getBusinessType(),PayOrderBusinessTypeEnum.NFT_CARD.getCode());
        goodsInfo.setGoodsType(isPhysicalGoods?"1":"0");
        goodsInfo.setGoodsPrice(businessOrder.getRealPrice());
        goodsInfo.setGoodsNums(businessOrder.getPurchaseNum());
        request.setGoodsInfos(Collections.singletonList(goodsInfo));
        request.setVersion("1.1");
        //签名
        String waitSignature = SignatureHelper.prepareSignData(request);
        log.info("待签名数据:" + waitSignature);
        String sign = RSASignature.sign(waitSignature, privateKey);
        request.setSign(sign);
        String str = HttpsUtils.post(payCenterHost+"/nx2cloud/nx2cloud-app-pay/payOpenApi/preOrderPay", request);
        if(StringUtils.isNotBlank(str)){
            com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(str);
            if ("0".equals(jsonObject.getString("code"))) {
                com.alibaba.fastjson.JSONObject data = jsonObject.getJSONObject("data");
                String signResult = data.getString("sign");
                data.remove("sign");
                //排序
                String signData = SignatureHelper.prepareSignData(data.getInnerMap());
                log.info("待验签数据:" + signData);
                if (RSASignature.verify(signData, Base64.getDecoder().decode(signResult), publicKey)) {
                    log.info("验签成功");
                    PayCenterArgsResponseV3 responseV3 = new PayCenterArgsResponseV3();
                    responseV3.setPayCenterVersion("v3");
                    responseV3.setPayCenterUrl(payCenterPageUrl);
                    PayCenterPayParamV3 payParamV3 = new PayCenterPayParamV3();
                    payParamV3.setPrepayId(data.getString("prepayId"));
                    payParamV3.setAppId(appId);
                    payParamV3.setTimeStamp(request.getTimestamp());
                    payParamV3.setNonceStr(IdUtil.getSnowflakeNextIdStr());
                    payParamV3.setPackage_("prepayId="+data.getString("prepayId"));
                    payParamV3.setSignType("RSA");
                    payParamV3.setIsSplitAccount(request.getIsSplitAccount());
                    payParamV3.setPaymentResults(true);
                    payParamV3.setBackUrl(addOrderArgs(backUrl,request.getOrderNo()));
                    String waitSignature1 = SignatureHelper.prepareSignData(payParamV3);
                    waitSignature1 = waitSignature1.replace("package_=", "package=");
                    log.info("payParamV3 待签名数据:" + waitSignature1);
                    sign = RSASignature.sign(waitSignature1, privateKey);
                    payParamV3.setSign(sign);
                    responseV3.setPayParam(payParamV3);
                    return responseV3;
                } else {
                    log.error("验签失败");
                    throw new ChainException(ErrorMessage.ORDER_CREATE_FAILED);
                }
            } else {
                log.error("预下单失败，响应结果:{}", str);
                throw new ChainException(ErrorMessage.ORDER_CREATE_FAILED);
            }
        }else {
            log.error("预下单失败，响应结果为空");
            throw new ChainException(ErrorMessage.ORDER_CREATE_FAILED);
        }
    }
}
